package com.zz.study.sharding.util;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class BeanUtil {
    /**
     * 大小写可以忽略
     * 下划线 _ 被忽略
     * NULL值和空字符串不会覆盖新值
     *
     * @param source
     * @param target
     * @param <T>
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static <T> T copyProperties(Map<String,Object> source, Class<T> bean) throws Exception {
        Map<String, Object> sourceMap = new HashMap<String, Object>();
        source.entrySet().forEach(entry -> {
            String key = entry.getKey().toLowerCase().replace("_", "");
            sourceMap.put(key,  entry.getValue());
        });
        T target =  bean.newInstance();
        CacheFieldMap.getFieldMap(bean).values().forEach((it) -> {
            Object field = sourceMap.get(it.getName().toLowerCase().replace("_", ""));
            if (field != null) {
                it.setAccessible(true);
                try {
                    if(field !=null && StringUtils.isNotEmpty(field.toString())){
                        if(it.getType().equals(Date.class)){
                            Date tempTime = DateUtil.formatDate(field.toString(),"yyyy-MM-dd HH:mm:ss");
                            it.set(target, tempTime);
                        }else if(it.getType().equals(Integer.class)){
                            it.set(target, Integer.valueOf(field.toString()));
                        }else if(it.getType().equals(Double.class)){
                            it.set(target, Double.valueOf(field.toString()));
                        }else if(it.getType().equals(Float.class)){
                            it.set(target, Float.valueOf(field.toString()));
                        }else if(it.getType().equals(Long.class)){
                            it.set(target, Long.valueOf(field.toString()));
                        }else{
                            it.set(target, field);
                        }

                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        return target;
    }
    
    
    public static <T> List<T> copyProperties(List<Map<String,Object>> source, Class<T> target) {
    	List<T> res = new ArrayList<T>();
    	source.forEach(s -> {
    		try {
				res.add(copyProperties(s, target));
			} catch (Exception e) {
				e.printStackTrace();
			}
    	});
    	return res;
    }
 
    private static class CacheFieldMap {
        private static Map<String, Map<String, Field>> cacheMap = new HashMap<>();
        private static Map<String, Field> getFieldMap(Class<?> clazz) {
            Map<String, Field> result = cacheMap.get(clazz.getName());
            if (result == null) {
                synchronized (CacheFieldMap.class) {
                    if (result == null) {
                        Map<String, Field> fieldMap = new HashMap<>();
                        for (Field field : clazz.getDeclaredFields()) {                      
                            fieldMap.put(field.getName().toLowerCase().replace("_", ""), field);
                        }
                        cacheMap.put(clazz.getName(), fieldMap);
                        result = cacheMap.get(clazz.getName());
                    }
                }
            }
            return result;
        }
    }

    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> function) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(function.apply(t), Boolean.TRUE) == null;
    }


    public static Function<Map<String,Object>, String> distinctByKeyFieldFunction(String fieldName) {
        return (Map<String,Object> bean) -> bean.get(fieldName).toString() ;
    }

    public static List<Map<String,Object>> distinctByKeyField(List<Map<String,Object>> originalList,String fieldName) {
        List<Map<String,Object>> distinctList = originalList.stream().filter(distinctByKey(distinctByKeyFieldFunction(fieldName))).collect(Collectors.toList());
       return distinctList;

    }
    

 
}